// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using iPanel.Components.Dialogs;
using iPanel.Components.Layout;
using iPanel.Extensions;
using iPanel.Model.Otlp;
using iPanel.Resources;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;

namespace iPanel.Components.Pages;

/// <summary>
/// 结构化日志页面组件，用于显示和管理结构化日志数据。
/// 实现了 IPageWithSessionAndUrlState 接口，支持会话和 URL 状态管理。
/// </summary>
public partial class StructuredLogs : IPageWithSessionAndUrlState<StructuredLogs.StructuredLogsPageViewModel, StructuredLogs.StructuredLogsPageState>
{
    // 定义网格列名称常量
    private const string ResourceColumn = nameof(ResourceColumn);
    private const string LogLevelColumn = nameof(LogLevelColumn);
    private const string TimestampColumn = nameof(TimestampColumn);
    private const string MessageColumn = nameof(MessageColumn);
    private const string TraceColumn = nameof(TraceColumn);
    private const string ActionsColumn = nameof(ActionsColumn);

    /// <summary>
    /// 表示所有应用程序的选择视图模型。
    /// </summary>
    private SelectViewModel<ResourceTypeDetails> _allApplication = default!;

    /// <summary>
    /// 总条目页脚组件的引用，用于显示总条目数。
    /// </summary>
    private TotalItemsFooter _totalItemsFooter = default!;

    /// <summary>
    /// 存储总条目数。
    /// </summary>
    private int _totalItemsCount;

    /// <summary>
    /// 存储所有应用程序的列表。
    /// </summary>
    private List<OtlpApplication> _applications = default!;

    /// <summary>
    /// 存储应用程序的选择视图模型列表。
    /// </summary>
    private List<SelectViewModel<ResourceTypeDetails>> _applicationViewModels = default!;

    /// <summary>
    /// 存储日志级别的选择视图模型列表。
    /// </summary>
    private List<SelectViewModel<LogLevel?>> _logLevels = default!;

    /// <summary>
    /// 应用程序数据订阅对象，用于监听新应用程序的添加。
    /// </summary>
    private Subscription? _applicationsSubscription;

    /// <summary>
    /// 日志数据订阅对象，用于监听新日志的添加。
    /// </summary>
    private Subscription? _logsSubscription;

    /// <summary>
    /// 标记应用程序是否发生变化。
    /// </summary>
    private bool _applicationChanged;

    /// <summary>
    /// 存储在详情视图打开之前聚焦的元素 ID。
    /// </summary>
    private string? _elementIdBeforeDetailsViewOpened;

    /// <summary>
    /// 页面内容布局组件的引用，用于管理页面布局。
    /// </summary>
    private AspirePageContentLayout? _contentLayout;

    /// <summary>
    /// 存储过滤文本。
    /// </summary>
    private string _filter = string.Empty;

    /// <summary>
    /// 数据网格组件的引用，用于显示日志数据。
    /// </summary>
    private FluentDataGrid<OtlpLogEntry> _dataGrid = null!;

    /// <summary>
    /// 网格列管理器，用于管理网格列的配置。
    /// </summary>
    private GridColumnManager _manager = null!;

    /// <summary>
    /// 存储网格列的列表。
    /// </summary>
    private IList<GridColumn> _gridColumns = null!;

    /// <summary>
    /// 列调整大小的标签，用于显示调整大小的提示信息。
    /// </summary>
    private ColumnResizeLabels _resizeLabels = ColumnResizeLabels.Default;

    /// <summary>
    /// 列排序的标签，用于显示排序的提示信息。
    /// </summary>
    private ColumnSortLabels _sortLabels = ColumnSortLabels.Default;

    /// <summary>
    /// 获取结构化日志页面的基础路径。
    /// </summary>
    public string BasePath => DashboardUrls.StructuredLogsBasePath;

    /// <summary>
    /// 获取会话存储的键，用于存储页面状态。
    /// </summary>
    public string SessionStorageKey => BrowserStorageKeys.StructuredLogsPageState;

    /// <summary>
    /// 获取或设置结构化日志页面的视图模型。
    /// </summary>
    public StructuredLogsPageViewModel PageViewModel { get; set; } = null!;

    [Inject]
    public required IToastService ToastService { get; init; }

    /// <summary>
    /// 注入的遥测数据仓库，用于获取和管理遥测数据。
    /// </summary>
    [Inject]
    public required TelemetryRepository TelemetryRepository { get; init; }

    /// <summary>
    /// 注入的结构化日志视图模型，用于处理结构化日志数据。
    /// </summary>
    [Inject]
    public required StructuredLogsViewModel ViewModel { get; init; }

    /// <summary>
    /// 注入的对话框服务，用于显示对话框。
    /// </summary>
    [Inject]
    public required IDialogService DialogService { get; init; }

    /// <summary>
    /// 注入的会话存储服务，用于存储和获取会话数据。
    /// </summary>
    [Inject]
    public required ISessionStorage SessionStorage { get; init; }

    /// <summary>
    /// 注入的导航管理器，用于处理页面导航。
    /// </summary>
    [Inject]
    public required NavigationManager NavigationManager { get; init; }

    /// <summary>
    /// 注入的浏览器时间提供程序，用于获取时间信息。
    /// </summary>
    [Inject]
    public required BrowserTimeProvider TimeProvider { get; init; }

    /// <summary>
    /// 注入的日志记录器，用于记录日志信息。
    /// </summary>
    [Inject]
    public required ILogger<StructuredLogs> Logger { get; init; }

    /// <summary>
    /// 注入的维度管理器，用于处理视图端口信息的变化。
    /// </summary>
    [Inject]
    public required DimensionManager DimensionManager { get; set; }

    /// <summary>
    /// 注入的仪表盘选项配置，用于获取仪表盘的配置信息。
    /// </summary>
    [Inject]
    public required IOptions<DashboardOptions> DashboardOptions { get; init; }

    /// <summary>
    /// 注入的消息服务，用于显示消息提示。
    /// </summary>
    [Inject]
    public required IMessageService MessageService { get; init; }

    /// <summary>
    /// 注入的暂停管理器，用于管理数据的暂停和恢复。
    /// </summary>
    [Inject]
    public required PauseManager PauseManager { get; init; }

    /// <summary>
    /// 级联参数，获取视图端口信息。
    /// </summary>
    [CascadingParameter]
    public required ViewportInformation ViewportInformation { get; set; }

    /// <summary>
    /// 页面参数，获取应用程序名称。
    /// </summary>
    [Parameter]
    public string? ApplicationName { get; set; }

    /// <summary>
    /// 页面参数，从查询字符串中获取跟踪 ID。
    /// </summary>
    [Parameter]
    [SupplyParameterFromQuery]
    public string? TraceId { get; set; }

    /// <summary>
    /// 页面参数，从查询字符串中获取跨度 ID。
    /// </summary>
    [Parameter]
    [SupplyParameterFromQuery]
    public string? SpanId { get; set; }

    /// <summary>
    /// 页面参数，从查询字符串中获取日志级别文本。
    /// </summary>
    [Parameter]
    [SupplyParameterFromQuery(Name = "logLevel")]
    public string? LogLevelText { get; set; }

    /// <summary>
    /// 页面参数，从查询字符串中获取序列化的过滤器。
    /// </summary>
    [Parameter]
    [SupplyParameterFromQuery(Name = "filters")]
    public string? SerializedFilters { get; set; }

    /// <summary>
    /// 获取或设置选中的日志条目视图模型。
    /// </summary>
    public StructureLogsDetailsViewModel? SelectedLogEntry { get; set; }

    /// <summary>
    /// 异步获取数据网格的日志数据。
    /// </summary>
    /// <param name="request">数据网格的请求信息，包含起始索引和请求数量。</param>
    /// <returns>包含日志条目和总条目数的结果。</returns>
    private async ValueTask<GridItemsProviderResult<OtlpLogEntry>> GetData(GridItemsProviderRequest<OtlpLogEntry> request)
    {
        // 设置视图模型的起始索引和请求数量
        ViewModel.StartIndex = request.StartIndex;
        ViewModel.Count = request.Count ?? DashboardUIHelpers.DefaultDataGridResultCount;

        // 从视图模型中获取日志数据
        var logs = ViewModel.GetLogs();

        // 更新总条目数并刷新总条目页脚的显示
        _totalItemsCount = logs.TotalItemCount;
        //_totalItemsFooter.UpdateDisplayedCount(_totalItemsCount);

        // 标记已查看错误日志
        TelemetryRepository.MarkViewedErrorLogs(ViewModel.ApplicationKey);

        // 返回日志条目和总条目数的结果
        return GridItemsProviderResult.From(logs.Items, logs.TotalItemCount);
    }

    protected async Task RefreshDataAsync()
    {
        ToastService.ShowProgressToast(new()
        {
            Id = $"RefreshDataAsync",
            Intent = ToastIntent.Progress,
            Title = "正在刷新",
            Content = new ProgressToastContent()
            {
                Details = "稍等片刻，正在加载最新数据...",
            },
        });
        ViewModel.ClearData();
        UpdateApplications();
        await InvokeAsync(async () =>
        {
            try
            {
                await _dataGrid.SafeRefreshDataAsync();
                ToastService.ClearAll();
                ToastService.ShowSuccess("已加载完成.");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
                ToastService.ClearAll();
                ToastService.ShowError("发生错误:" + ex.Message);
            }

        });
    }

    /// <summary>
    /// 组件初始化完成后的异步处理方法。
    /// </summary>
    /// <returns>表示异步操作的任务。</returns>
    protected override Task OnInitializedAsync()
    {
        // 创建网格列的标签
        (_resizeLabels, _sortLabels) = DashboardUIHelpers.CreateGridLabels(ControlsStringsLoc);

        // 初始化网格列
        _gridColumns = [
            new GridColumn(Name: ResourceColumn, DesktopWidth: "2fr", MobileWidth: "1fr"),
            new GridColumn(Name: LogLevelColumn, DesktopWidth: "1fr"),
            new GridColumn(Name: TimestampColumn, DesktopWidth: "1.5fr"),
            new GridColumn(Name: MessageColumn, DesktopWidth: "5fr", "2.5fr"),
            new GridColumn(Name: TraceColumn, DesktopWidth: "1fr"),
            new GridColumn(Name: ActionsColumn, DesktopWidth: "1fr", MobileWidth: "0.8fr")
        ];

        // 如果存在跟踪 ID，则添加跟踪 ID 过滤器
        if (!string.IsNullOrEmpty(TraceId))
        {
            ViewModel.AddFilter(new TelemetryFilter
            {
                Field = KnownStructuredLogFields.TraceIdField,
                Condition = FilterCondition.Equals,
                Value = TraceId
            });
        }

        // 如果存在跨度 ID，则添加跨度 ID 过滤器
        if (!string.IsNullOrEmpty(SpanId))
        {
            ViewModel.AddFilter(new TelemetryFilter
            {
                Field = KnownStructuredLogFields.SpanIdField,
                Condition = FilterCondition.Equals,
                Value = SpanId
            });
        }

        // 初始化所有应用程序的选择视图模型
        _allApplication = new()
        {
            Id = null,
            Name = ControlsStringsLoc[nameof(iPanel.Resources.ControlsStrings.LabelAll)]
        };

        // 初始化日志级别的选择视图模型列表
        _logLevels = new List<SelectViewModel<LogLevel?>>
        {
            new SelectViewModel<LogLevel?> { Id = null, Name = ControlsStringsLoc[nameof(iPanel.Resources.ControlsStrings.LabelAll)] },
            new SelectViewModel<LogLevel?> { Id = LogLevel.Trace, Name = "Trace" },
            new SelectViewModel<LogLevel?> { Id = LogLevel.Debug, Name = "Debug" },
            new SelectViewModel<LogLevel?> { Id = LogLevel.Information, Name = "Information" },
            new SelectViewModel<LogLevel?> { Id = LogLevel.Warning, Name = "Warning" },
            new SelectViewModel<LogLevel?> { Id = LogLevel.Error, Name = "Error" },
            new SelectViewModel<LogLevel?> { Id = LogLevel.Critical, Name = "Critical" },
        };

        // 初始化页面视图模型
        PageViewModel = new StructuredLogsPageViewModel
        {
            SelectedLogLevel = _logLevels[0],
            SelectedApplication = _allApplication
        };

        // 更新应用程序列表
        UpdateApplications();

        // 订阅新应用程序的添加事件
        if (false)
            _applicationsSubscription = TelemetryRepository.OnNewApplications(() => InvokeAsync(() =>
            {
                UpdateApplications();
                StateHasChanged();
            }));

        return Task.CompletedTask;
    }

    /// <summary>
    /// 组件参数设置完成后的异步处理方法。
    /// </summary>
    /// <returns>表示异步操作的任务。</returns>
    protected override async Task OnParametersSetAsync()
    {
        // 初始化视图模型
        if (await this.InitializeViewModelAsync())
        {
            return;
        }

        // 更新订阅
        UpdateSubscription();
    }

    /// <summary>
    /// 更新应用程序列表。
    /// </summary>
    private void UpdateApplications()
    {
        // 从遥测数据仓库中获取所有应用程序
        _applications = TelemetryRepository.GetApplications();

        // 创建应用程序的选择视图模型列表
        _applicationViewModels = ApplicationsSelectHelpers.CreateApplications(_applications);

        // 在列表开头插入所有应用程序的选择视图模型
        _applicationViewModels.Insert(0, _allApplication);
    }

    /// <summary>
    /// 处理选中应用程序变更的异步方法。
    /// </summary>
    /// <returns>表示异步操作的任务。</returns>
    private Task HandleSelectedApplicationChangedAsync()
    {
        // 标记应用程序发生变化
        _applicationChanged = true;

        // 在视图模型变更后执行异步操作
        return this.AfterViewModelChangedAsync(_contentLayout, waitToApplyMobileChange: true);
    }

    /// <summary>
    /// 处理选中日志级别变更的异步方法。
    /// </summary>
    /// <returns>表示异步操作的任务。</returns>
    private async Task HandleSelectedLogLevelChangedAsync()
    {
        // 标记应用程序发生变化
        _applicationChanged = true;

        // 清除选中的日志条目
        await ClearSelectedLogEntryAsync();

        // 在视图模型变更后执行异步操作
        await this.AfterViewModelChangedAsync(_contentLayout, waitToApplyMobileChange: true);
    }

    /// <summary>
    /// 更新日志数据的订阅。
    /// </summary>
    private void UpdateSubscription()
    {
        return;
        // 如果订阅不存在或应用程序键发生变化，则重新订阅
        if (_logsSubscription is null || _logsSubscription.ApplicationKey != PageViewModel.SelectedApplication.Id?.GetApplicationKey())
        {
            _logsSubscription?.Dispose();
            _logsSubscription = TelemetryRepository.OnNewLogs(PageViewModel.SelectedApplication.Id?.GetApplicationKey(), SubscriptionType.Read, async () =>
            {
                // 清除视图模型中的数据
                ViewModel.ClearData();

                // 安全地刷新数据网格的数据
                await InvokeAsync(_dataGrid.SafeRefreshDataAsync);
            });
        }
    }

    /// <summary>
    /// 异步显示日志条目的属性详情。
    /// </summary>
    /// <param name="entry">要显示详情的日志条目。</param>
    /// <param name="buttonId">触发操作的按钮 ID。</param>
    /// <returns>表示异步操作的任务。</returns>
    private async Task OnShowPropertiesAsync(OtlpLogEntry entry, string? buttonId)
    {
        // 记录详情视图打开之前聚焦的元素 ID
        _elementIdBeforeDetailsViewOpened = buttonId;

        // 如果当前选中的日志条目与传入的日志条目相同，则清除选中的日志条目
        if (SelectedLogEntry?.LogEntry.InternalId == entry.InternalId)
        {
            await ClearSelectedLogEntryAsync();
        }
        else
        {
            // 创建新的日志条目详情视图模型
            var logEntryViewModel = new StructureLogsDetailsViewModel
            {
                LogEntry = entry
            };

            // 设置选中的日志条目
            SelectedLogEntry = logEntryViewModel;
        }
    }

    /// <summary>
    /// 异步清除选中的日志条目。
    /// </summary>
    /// <param name="causedByUserAction">是否由用户操作触发。</param>
    /// <returns>表示异步操作的任务。</returns>
    private async Task ClearSelectedLogEntryAsync(bool causedByUserAction = false)
    {
        // 清除选中的日志条目
        SelectedLogEntry = null;

        // 如果由用户操作触发且之前有聚焦的元素 ID，则聚焦该元素
        if (_elementIdBeforeDetailsViewOpened is not null && causedByUserAction)
        {
            await JS.InvokeVoidAsync("focusElement", _elementIdBeforeDetailsViewOpened);
        }

        // 清除之前聚焦的元素 ID
        _elementIdBeforeDetailsViewOpened = null;
    }

    /// <summary>
    /// 异步打开过滤器对话框。
    /// </summary>
    /// <param name="entry">要编辑的过滤器条目，如果为 null 则表示添加新过滤器。</param>
    /// <returns>表示异步操作的任务。</returns>
    private async Task OpenFilterAsync(TelemetryFilter? entry)
    {
        // 如果页面内容布局组件存在，则关闭移动工具栏
        if (_contentLayout is not null)
        {
            await _contentLayout.CloseMobileToolbarAsync();
        }

        // 设置对话框标题
        var title = entry is not null ? FilterLoc[nameof(StructuredFiltering.DialogTitleEditFilter)] : FilterLoc[nameof(StructuredFiltering.DialogTitleAddFilter)];

        // 设置对话框参数
        var parameters = new DialogParameters
        {
            OnDialogResult = DialogService.CreateDialogCallback(this, HandleFilterDialog),
            Title = title,
            DismissTitle = DialogsLoc[nameof(iPanel.Resources.Dialogs.DialogCloseButtonText)],
            Alignment = HorizontalAlignment.Right,
            PrimaryAction = null,
            SecondaryAction = null,
            Width = "450px"
        };

        // 设置过滤器对话框视图模型
        var data = new FilterDialogViewModel
        {
            Filter = entry,
            PropertyKeys = TelemetryRepository.GetLogPropertyKeys(PageViewModel.SelectedApplication.Id?.GetApplicationKey()),
            KnownKeys = KnownStructuredLogFields.AllFields,
            GetFieldValues = TelemetryRepository.GetLogsFieldValues
        };

        // 显示过滤器对话框
        await DialogService.ShowPanelAsync<FilterDialog>(data, parameters);
    }

    /// <summary>
    /// 处理过滤器对话框结果的异步方法。
    /// </summary>
    /// <param name="result">对话框的结果。</param>
    /// <returns>表示异步操作的任务。</returns>
    private async Task HandleFilterDialog(DialogResult result)
    {
        // 如果对话框结果包含过滤器结果
        if (result.Data is FilterDialogResult filterResult && filterResult.Filter is TelemetryFilter filter)
        {
            if (filterResult.Delete)
            {
                // 删除过滤器
                ViewModel.RemoveFilter(filter);
            }
            else if (filterResult.Add)
            {
                // 添加过滤器并清除选中的日志条目
                ViewModel.AddFilter(filter);
                await ClearSelectedLogEntryAsync();
            }
            else if (filterResult.Enable)
            {
                // 启用过滤器
                filter.Enabled = true;
            }
            else if (filterResult.Disable)
            {
                // 禁用过滤器
                filter.Enabled = false;
            }
        }

        // 在视图模型变更后执行异步操作
        await this.AfterViewModelChangedAsync(_contentLayout, waitToApplyMobileChange: true);
    }

    /// <summary>
    /// 处理过滤器绑定后的异步方法。
    /// </summary>
    /// <returns>表示异步操作的任务。</returns>
    private async Task HandleAfterFilterBindAsync()
    {
        // 设置视图模型的过滤文本
        ViewModel.FilterText = _filter;

        // 安全地刷新数据网格的数据
        await InvokeAsync(_dataGrid.SafeRefreshDataAsync);

        // 如果过滤文本为空，则直接返回
        if (string.IsNullOrEmpty(_filter))
        {
            return;
        }

        // 清除选中的日志条目
        await ClearSelectedLogEntryAsync();
    }

    /// <summary>
    /// 获取应用程序的资源名称。
    /// </summary>
    /// <param name="app">要获取资源名称的应用程序视图。</param>
    /// <returns>应用程序的资源名称。</returns>
    private string GetResourceName(OtlpApplicationView app) => OtlpApplication.GetResourceName(app.Application, _applications);

    /// <summary>
    /// 获取日志条目行的 CSS 类名。
    /// </summary>
    /// <param name="entry">要获取 CSS 类名的日志条目。</param>
    /// <returns>日志条目行的 CSS 类名。</returns>
    private string GetRowClass(OtlpLogEntry entry)
    {
        // 如果当前选中的日志条目与传入的日志条目相同，则返回选中行的 CSS 类名
        if (entry.InternalId == SelectedLogEntry?.LogEntry.InternalId)
        {
            return "selected-row";
        }
        else
        {
            // 否则返回根据日志级别生成的 CSS 类名
            return $"log-row-{entry.Severity.ToString().ToLowerInvariant()}";
        }
    }

    /// <summary>
    /// 获取过滤器菜单的菜单项列表。
    /// </summary>
    /// <returns>过滤器菜单的菜单项列表。</returns>
    private List<MenuButtonItem> GetFilterMenuItems()
    {
        // 调用帮助方法获取过滤器菜单的菜单项列表
        return this.GetFilterMenuItems(
            ViewModel.Filters,
            ViewModel.ClearFilters,
            OpenFilterAsync,
            FilterLoc,
            DialogsLoc,
            _contentLayout);
    }

    /// <summary>
    /// 组件渲染完成后的异步处理方法。
    /// </summary>
    /// <param name="firstRender">是否为首次渲染。</param>
    /// <returns>表示异步操作的任务。</returns>
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        // 如果应用程序发生变化，则重置连续滚动位置
        if (_applicationChanged)
        {
            //await JS.InvokeVoidAsync("resetContinuousScrollPosition");
            _applicationChanged = false;
        }

        // 如果是首次渲染，则初始化连续滚动并订阅视图端口信息变化事件
        if (firstRender)
        {
            //await JS.InvokeVoidAsync("initializeContinuousScroll");
            DimensionManager.OnViewportInformationChanged += OnBrowserResize;
        }
    }

    /// <summary>
    /// 处理浏览器窗口大小变化的方法。
    /// </summary>
    /// <param name="o">事件源对象。</param>
    /// <param name="args">事件参数。</param>
    private void OnBrowserResize(object? o, EventArgs args)
    {
        // 异步重置连续滚动位置并重新初始化连续滚动
        InvokeAsync(async () =>
        {
            //await JS.InvokeVoidAsync("resetContinuousScrollPosition");
            //await JS.InvokeVoidAsync("initializeContinuousScroll");
        });
    }

    /// <summary>
    /// 获取暂停文本，如果结构化日志已暂停，则显示暂停开始时间。
    /// </summary>
    private string? PauseText => PauseManager.AreStructuredLogsPaused(out var startTime)
        ? string.Format(
            CultureInfo.CurrentCulture,
            Loc[nameof(iPanel.Resources.StructuredLogs.PauseInProgressText)],
            FormatHelpers.FormatTimeWithOptionalDate(TimeProvider, startTime.Value, MillisecondsDisplay.Truncated))
        : null;

    /// <summary>
    /// 释放资源的方法，用于取消订阅和移除事件处理程序。
    /// </summary>
    public void Dispose()
    {
        // 释放应用程序数据订阅对象
        _applicationsSubscription?.Dispose();

        // 释放日志数据订阅对象
        _logsSubscription?.Dispose();

        // 移除视图端口信息变化事件的处理程序
        DimensionManager.OnViewportInformationChanged -= OnBrowserResize;
    }

    /// <summary>
    /// 根据可序列化的视图模型生成 URL。
    /// </summary>
    /// <param name="serializable">可序列化的结构化日志页面状态。</param>
    /// <returns>生成的 URL。</returns>
    public string GetUrlFromSerializableViewModel(StructuredLogsPageState serializable)
    {
        // 如果存在过滤器，则将其序列化为字符串
        var filters = (serializable.Filters.Count > 0) ? TelemetryFilterFormatter.SerializeFiltersToString(serializable.Filters) : null;

        // 生成结构化日志的 URL
        var url = DashboardUrls.StructuredLogsUrl(
            resource: serializable.SelectedApplication,
            logLevel: serializable.LogLevelText,
            filters: filters);

        return url;
    }

    /// <summary>
    /// 将视图模型转换为可序列化的状态。
    /// </summary>
    /// <returns>可序列化的结构化日志页面状态。</returns>
    public StructuredLogsPageState ConvertViewModelToSerializable()
    {
        return new StructuredLogsPageState
        {
            LogLevelText = PageViewModel.SelectedLogLevel.Id?.ToString().ToLowerInvariant(),
            SelectedApplication = PageViewModel.SelectedApplication.Id is not null ? PageViewModel.SelectedApplication.Name : null,
            Filters = ViewModel.Filters
        };
    }

    /// <summary>
    /// 异步根据查询参数更新视图模型。
    /// </summary>
    /// <param name="viewModel">要更新的结构化日志页面视图模型。</param>
    /// <returns>表示异步操作的任务。</returns>
    public async Task UpdateViewModelFromQueryAsync(StructuredLogsPageViewModel viewModel)
    {
        // 根据应用程序名称更新选中的应用程序
        viewModel.SelectedApplication = _applicationViewModels.GetApplication(Logger, ApplicationName, canSelectGrouping: true, _allApplication);

        // 设置视图模型的应用程序键
        ViewModel.ApplicationKey = PageViewModel.SelectedApplication.Id?.GetApplicationKey();

        // 如果存在日志级别文本，则解析并设置选中的日志级别
        if (LogLevelText is not null && Enum.TryParse<LogLevel>(LogLevelText, ignoreCase: true, out var logLevel))
        {
            PageViewModel.SelectedLogLevel = _logLevels.SingleOrDefault(e => e.Id == logLevel) ?? _logLevels[0];
        }
        else
        {
            // 否则设置为默认的日志级别
            PageViewModel.SelectedLogLevel = _logLevels[0];
        }

        // 设置视图模型的日志级别
        ViewModel.LogLevel = PageViewModel.SelectedLogLevel.Id;

        // 如果存在序列化的过滤器，则反序列化并添加到视图模型中
        if (SerializedFilters is not null)
        {
            var filters = TelemetryFilterFormatter.DeserializeFiltersFromString(SerializedFilters);

            if (filters.Count > 0)
            {
                // 清除现有过滤器
                ViewModel.ClearFilters();

                // 添加反序列化后的过滤器
                foreach (var filter in filters)
                {
                    ViewModel.AddFilter(filter);
                }
            }
        }

        // 安全地刷新数据网格的数据
        await InvokeAsync(_dataGrid.SafeRefreshDataAsync);
    }

    /// <summary>
    /// 清除指定应用程序的结构化日志。
    /// </summary>
    /// <param name="key">要清除日志的应用程序键。</param>
    /// <returns>表示异步操作的任务。</returns>
    private async Task ClearStructureLogs(ApplicationKey? key)
    {
        // 调用遥测数据仓库的方法清除结构化日志
        TelemetryRepository.ClearStructuredLogs(key);
        ToastService.ShowSuccess(string.Format("{0}日志已清除", key));
        await RefreshDataAsync();
    }

    /// <summary>
    /// 结构化日志页面的视图模型，包含选中的应用程序和日志级别。
    /// </summary>
    public class StructuredLogsPageViewModel
    {
        /// <summary>
        /// 获取或设置选中的应用程序。
        /// </summary>
        public required SelectViewModel<ResourceTypeDetails> SelectedApplication { get; set; }

        /// <summary>
        /// 获取或设置选中的日志级别。
        /// </summary>
        public SelectViewModel<LogLevel?> SelectedLogLevel { get; set; } = default!;
    }

    /// <summary>
    /// 结构化日志页面的状态模型，用于序列化和存储页面状态。
    /// </summary>
    public class StructuredLogsPageState
    {
        /// <summary>
        /// 获取或设置选中的应用程序名称。
        /// </summary>
        public string? SelectedApplication { get; set; }

        /// <summary>
        /// 获取或设置日志级别文本。
        /// </summary>
        public string? LogLevelText { get; set; }

        /// <summary>
        /// 获取或设置过滤器集合。
        /// </summary>
        public required IReadOnlyCollection<TelemetryFilter> Filters { get; set; }
    }
}
